/*NOTICE

This software was produced for the U. S. Government
under Contract No. FA8721-09-C-0002, and is
subject to the Rights in Noncommercial Computer Software
and Noncommercial Computer Software Documentation Clause
(DFARS) 252.227-7014 (JUN 1995)

(c) 2009 The MITRE Corporation. All Rights Reserved.
*/
package org.mitre.xmltransform;

import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public abstract class XmlInputDocument {
	public XmlInputDocument(File pInputFile) {
		mInputFile = pInputFile;
		setupXPath();
		parseInput();
		updateNamespaces(mNamespaces);
	}
	
	public String getFileName() {
		return mInputFile.getName();
	}
	
	private boolean parseInput() {
		try {
			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			dbf.setNamespaceAware(true); // XPath's with namespace won't work if you don't make this true
	        DocumentBuilder xmlBuilder = dbf.newDocumentBuilder();
	        mXmlInputDocument = xmlBuilder.parse(mInputFile);	        
			return true;
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
	}
	
	protected NamedNodeMap getNamespaceAttributes() {
        return mXmlInputDocument.getDocumentElement().getAttributes();
	}
		
	private boolean setupXPath() {
		mNamespaces = new XPathNamespaceContextImpl();
		addNamespaces(mNamespaces);
		
		mVariableResolver = new XPathVariableResolverImpl();
		
		mXpath = XPathFactory.newInstance().newXPath();
		mXpath.setNamespaceContext(mNamespaces);
		mXpath.setXPathVariableResolver(mVariableResolver);
		return true;
	}

	public String getInputValue(String pExpression) {
		return getInputValue(mXmlInputDocument, pExpression);
	}
	
	public String getInputValue(Node pContext, String pExpression) {
		try {
			//System.out.println("value:" + pExpression);
			return mXpath.evaluate(pExpression, pContext);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}		
	}
	
	public Node getInputNode(String pExpression) {
		return getInputNode(mXmlInputDocument, pExpression);
	}
	
	public Node getInputNode(Node pContext, String pExpression) {
		try {
			//System.out.println("node:" + pExpression);
			return (Node)mXpath.evaluate(pExpression, pContext, XPathConstants.NODE);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public NodeList getInputNodes(String pExpression) {
		return getInputNodes(mXmlInputDocument, pExpression);
	}
		
	public NodeList getInputNodes(Node pContext, String pExpression) {
		try {
			//System.out.println("nodes:" + pExpression);
			return (NodeList)mXpath.evaluate(pExpression, pContext, XPathConstants.NODESET);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}		
	}
	
	public boolean evaluateBooleanInputExpression(String pExpression) {
		return evaluateBooleanInputExpression(mXmlInputDocument, pExpression);
	}
	
	public boolean evaluateBooleanInputExpression(Node pContext, String pExpression) {
		try {
			//System.out.println("bool:" + pExpression);
			Boolean result = (Boolean)mXpath.evaluate(pExpression, pContext, XPathConstants.BOOLEAN);
			return result.booleanValue();
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}		
		
	}
	
	public void setVariable(String pName, String pValue) {
		mVariableResolver.setVariable(pName, pValue);
	}

	
	public void resetVariables() {
		mVariableResolver.reset();
	}
	
	public String getNamespacePrefix(String pNamespace) {
		return mNamespaces.getPrefix(pNamespace);
	}

	public abstract String buildNodeName(Node pContext, String pFixedPrefix);
	protected abstract void addNamespaces(XPathNamespaceContextImpl pNamespaces);
	protected void updateNamespaces(XPathNamespaceContextImpl pNamespaces) {
		
	}

	private File mInputFile;
	private XPath mXpath;
	private Document mXmlInputDocument;
	private XPathNamespaceContextImpl mNamespaces;
	private XPathVariableResolverImpl mVariableResolver;
}
